//
//  CZSQLiteManager.swift
//  Database
//
//  Created by cc on 11/8/17.
//  Copyright © 2017 cc. All rights reserved.
//

import Foundation
import FMDB

//最大的数据库缓存时间，以秒为单位
private let maxDBCacheTime: TimeInterval = -5 * 24 * 60 * 60


/// SQLite 管理器
/*
    1.数据库本质上是保存在沙盒中的一个文件，首先需要创建并且打开数据库
        FMDB 使用的是 队列
    2.创建数据表
    3.增删改查
 
 */
class CZSQLiteManager {
    
    //单例， 全局数据库工具访问点
    static let shared = CZSQLiteManager()

    ///数据库对列
    let queue: FMDatabaseQueue
    
    ///构造函数
    private init() {
        //数据库的全路径
        let dbName = "status.db"
        var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
        
        path = (path as NSString).appendingPathComponent(dbName)
        
        print("数据库的路径" + path)
        
        //创建数据库队列, 同时创建或者打开数据库
        queue = FMDatabaseQueue(path: path)
        
        //打开数据库
        createTable()
        
        //注册通知 - 监听应用程序进入后台
        NotificationCenter.default.addObserver(self, selector: #selector(clearDBCache), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
        
    }
    
    deinit {
        //注销通知
        NotificationCenter.default.removeObserver(self)
    }
    
    /// 清理数据缓存
    @objc private func clearDBCache() {
        let dateString = Date.cz_dateString(delta: maxDBCacheTime)
        
        //准备SQL
        let sql = "DELETE FROM T_Status WHERE create_time < ?;"
        
        //执行SQL
        queue.inDatabase { (db) in
            if db.executeUpdate(sql, withArgumentsIn: [dateString]) == true {
                print(db.changes)
            }
        }
        
    }
    
}



// MARK: - 微博数据操作
extension CZSQLiteManager {
    
    /// 从数据库加载微博数据数组
    ///
    /// - Parameters:
    ///   - userId: 当前登录的用户帐号
    ///   - since_id: 返回ID比since_id大的微博
    ///   - max_id:   返回ID小于max_id的微博
    /// - Returns: 微博的字典的数组， 将数据库中的status字段对应的二进制数据反序列化，生成字典
    func loadStatus(userId: String, since_id: Int64 = 0, max_id: Int64 = 0) -> [[String: Any]] {
        //1.准备sql
        var sql = "SELECT * FROM T_Status \n"
        sql += "WHERE userId = \(userId) \n"
        
        //上拉/下拉
        if since_id > 0 {
            sql += "AND statusId > \(since_id) \n"
        } else if max_id > 0 {
            sql += "AND statusId < \(max_id) \n"
        }
        
        sql += "ORDER BY statusId DESC LIMIT 20;"
        
//        print( sql )
        //2. 执行
        let array = execRecordSet(sql: sql)
        
        //3.遍历数组, 将数组中的status反序列化
        var result = [[String: Any]]()
        
        for dict in array {
            //反序列化
            guard let jsonData = dict["status"] as? Data, let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] else {
                continue
            }
            
            
            //追加到数组
            result.append(json ?? [:])
            
        }
        
        return result
    }
    
    
    
    
    /*
        从网络加载结束后，返回的是微博的 字典数组，每一个字典对应一个完整的微博记录
        - 完整的微博记录中，包含微博的代号
        - 微博记录中，没有 当前登录的用户代号
     */
    
    
    /// 新增或者修改微博数据， 微博数据在刷新的时候可能会出现重叠
    ///
    /// - Parameters:
    ///   - userId: 当前登录用户的id
    ///   - array: 从网络获取的字典的数组
    func updateStatus(userId: String, array:[[String: Any]]) {
        //1. 准备SQL
        /*
         statusId: 要保存的微博代号
         userId： 当前登录的用户id
         status： 完整的微博字典的json 二进制数据
        */
        let sql = "INSERT OR REPLACE INTO T_Status(statusId, userId, status) VALUES (?, ?, ?);"
        
        
        //2. 执行SQL
        queue.inTransaction { (db, rollback) in
            
            //遍历数组，逐条插入微博数据
            for dict in array {
                
                //从字典获取微博代号 / 将字典序列化成二进制数据
                guard let statusId = dict["idstr"] as? String,  let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: []) else {
                    continue
                }
                
                
                //执行SQL
                if db.executeUpdate(sql, withArgumentsIn: [statusId, userId, jsonData]) == false {
                    //需要回滚
                    rollback.pointee = true
                    break
                }
        
            }
        }
        
    }
}



// MARK: - 创建数据表以及其他私有方法
extension CZSQLiteManager {

    /// 执行一个Sql，返回字典的数组
    ///
    /// - Parameter sql: sql
    /// - Returns: 字典的数组
    func execRecordSet(sql: String) -> [[String: Any]] {
        
        //结果数组
        var result = [[String: Any]]()
        
        //执行sql
        queue.inDatabase { (db) in
            guard let rs = db.executeQuery(sql, withArgumentsIn: []) else {
                return
            }
            
            //逐行 - 遍历结果集合
            while rs.next() {
                //1. 列数
                let colCount = rs.columnCount
                //2. 遍历所有列
                for col in 0..<colCount {
                    //3.取列名 -> Key /  值-> value
                    guard let name = rs.columnName(for: col), let value = rs.object(forColumnIndex: col) else {
                        continue
                    }
                    //4. 追加结果
                    result.append([name: value])
                    
                }
            }
        }
        
        return result
    }
    
    
    
    //创建数据表
    func createTable() {
        //1. SQL
        guard let path = Bundle.main.path(forResource: "status.sql", ofType: nil), let sql = try? String(contentsOfFile: path) else {
            return
        }
        
        //2. 执行SQL - FMDB 是串行队列，同步执行
        //保证同一时间，只有一个任务操作数据库，从而保证数据库的读写安全
        queue.inDatabase { (db) in
            if db.executeStatements(sql) == true {
                print("success")
            } else {
                print("failed")
            }
        }
        
        print("over")
    }
}





